from typing import Callable, Dict, Optional


class AutoTask:
    def __init__(self,
                 cmd_id: str,
                 display: str,
                 freq: int,
                 json_disable_setter: Callable[[bool], None],
                 exec_func: Callable[[], bool]):
        self.cmd_id = cmd_id
        self.display = display
        self.freq = max(1, int(freq))
        self.json_disable_setter = json_disable_setter
        self.exec_func = exec_func
        self.running = False
        self.count = 0
        self.next_ts = 0


class AutoTaskManager:
    """独立的定时发送任务管理器。

    - 允许多个任务并存，但同一指令(cmd_id)只有一个任务实例（是否运行由 running 标识控制）。
    - 不依赖GUI事件循环；由外部每秒调用 tick() 进行调度。
    """

    def __init__(self):
        self._tasks: Dict[str, AutoTask] = {}

    def start_task(self,
                   cmd_id: str,
                   display: str,
                   freq_sec: int,
                   json_disable_setter: Callable[[bool], None],
                   exec_func: Callable[[], bool],
                   now_ms: int,
                   connected: bool,
                   error_cb: Optional[Callable[[str], None]] = None) -> bool:
        if not connected:
            if error_cb:
                error_cb('TCP未连接，无法启用自动发送')
            return False
        task = self._tasks.get(cmd_id)
        if task is None:
            task = AutoTask(cmd_id, display, freq_sec, json_disable_setter, exec_func)
            self._tasks[cmd_id] = task
        else:
            task.display = display
            task.freq = max(1, int(freq_sec))
            task.json_disable_setter = json_disable_setter
            task.exec_func = exec_func
        if task.running:
            return True
        # 切换为运行中
        task.running = True
        # 立即执行一次（失败不计数，后续继续）
        try:
            ok = task.exec_func()
            if ok:
                task.count += 1
        except Exception as e:
            if error_cb:
                error_cb(f'自动发送失败: {e}')
        task.next_ts = now_ms + task.freq * 1000
        try:
            task.json_disable_setter(True)
        except Exception:
            pass
        return True

    def stop_task(self, cmd_id: str):
        task = self._tasks.get(cmd_id)
        if not task:
            return
        if task.running:
            task.running = False
            try:
                task.json_disable_setter(False)
            except Exception:
                pass

    def stop_all(self):
        for task in self._tasks.values():
            if task.running:
                task.running = False
                try:
                    task.json_disable_setter(False)
                except Exception:
                    pass

    def is_running(self, cmd_id: str) -> bool:
        t = self._tasks.get(cmd_id)
        return bool(t and t.running)

    def get_task(self, cmd_id: str) -> Optional[AutoTask]:
        return self._tasks.get(cmd_id)

    def tick(self, now_ms: int, connected: bool, error_cb: Optional[Callable[[str], None]] = None):
        if not connected:
            return
        for t in self._tasks.values():
            if not t.running:
                continue
            if now_ms >= t.next_ts:
                try:
                    ok = t.exec_func()
                    if ok:
                        t.count += 1
                except Exception as e:
                    if error_cb:
                        error_cb(f'自动发送失败: {e}')
                t.next_ts = now_ms + t.freq * 1000

    def summary_line(self) -> str:
        parts = []
        for t in self._tasks.values():
            state = '运行中' if t.running else '已停止'
            parts.append(f"{t.display} 每{t.freq}s 次数:{t.count} {state}")
        return ' | '.join(parts)


